home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / DDJMAG / DDJ9207.ZIP / VIEWER.ASC < prev    next >
Text File  |  1992-06-15  |  20KB  |  627 lines

  1. _GRAPHICS IMPORT FILTERS FOR WINDOWS APPLICATIONS_
  2. by Evangelo Prodromou
  3.  
  4. [LISTING ONE]
  5.  
  6. /****************************************************************************
  7.  
  8.     FILE   : Viewer.h
  9.  
  10.     PURPOSE: header file for graphic viewer
  11.  
  12. ) 1992, Evangelo Prodromou.  All rights reserved.
  13. ****************************************************************************/
  14.  
  15. /* Viewer Menu item definitions */
  16.  
  17. #define IDM_ABOUT       100
  18. #define IDC_STATIC      -1
  19.  
  20. /*  general-use string size. */
  21.  
  22. #define STRINGSIZE 511
  23.  
  24. /* The following definitions are data types defined by the Aldus
  25. ** Interface. */
  26.  
  27. typedef DWORD FILETYPE;
  28.  
  29. typedef struct {
  30.    unsigned    slippery : 1;        /* TRUE if file may disappear. */
  31.    unsigned    write : 1;           /* TRUE if open for write. */
  32.    unsigned    unnamed : 1;         /* TRUE if unnamed. */
  33.    unsigned    linked : 1;          /* Linked to an FS FCB. */
  34.    unsigned    mark : 1;            /* Generic mark bit. */
  35.    FILETYPE    fType;               /* The file type. */
  36. #define IBMFNSIZE 124
  37.    short       handle;              /* MS-DOS open file handle. */
  38.    char        fullName[IBMFNSIZE]; /* Device, path, file names. */
  39.    DWORD       filePos;          /* Our current file posn. */
  40. } FILESPEC, FAR *LPFILESPEC;
  41.  
  42. typedef short DC;
  43.  
  44. typedef struct {        /* --- PICTINFO for Windows --- */
  45.   HANDLE        hmf;    /* Global memory handle to the metafile */
  46.   RECT          bbox;   /* Tightly bounding rectangle in metafile units */
  47.   DC            inch;   /* Length of an inch in metafile units */
  48. } PICTINFO, FAR* LPPICTINFO;
  49.  
  50.  
  51. /* The following types are pointers to functions with the same arguments
  52. ** as those found in an Aldus-standard function.  They are necessary to
  53. ** make anonymous function calls. */
  54.  
  55. /* Version 1.0 filter functions */
  56.  
  57. typedef WORD (FAR PASCAL *PFN_INFO)   (short, LPSTR, HANDLE FAR*, HANDLE FAR*);
  58. typedef WORD (FAR PASCAL *PFN_IMPORT) (HDC, LPFILESPEC, LPPICTINFO, HANDLE);
  59. typedef void (FAR PASCAL *PFN_PREF)   (HANDLE, HWND, HANDLE, WORD);
  60.  
  61. /* Version 2.0 filter functions */
  62.  
  63. typedef WORD (FAR PASCAL *PFN_VER)    (DWORD, BOOL FAR *, WORD FAR *, WORD FAR *);
  64. typedef WORD (FAR PASCAL *PFN_ISMY)   (LPFILESPEC);
  65. typedef WORD (FAR PASCAL *PFN_PREF2)  (HANDLE, HANDLE, HANDLE FAR *, DWORD, FARPROC, LPFILESPEC);
  66. typedef WORD (FAR PASCAL *PFN_OUTPUT) (HDC, HDC, LPFILESPEC, LPSTR, LPPICTINFO, HANDLE, FARPROC, BOOL);
  67.  
  68. /* The following are function declarations for functions local to 
  69. ** this application. */
  70.  
  71. int PASCAL WinMain( HANDLE, HANDLE, LPSTR, int );
  72. long FAR PASCAL MainWndProc( HWND, unsigned, WORD, LONG );
  73. BOOL FAR PASCAL AboutDlgProc( HWND, unsigned, WORD, LONG );
  74. BOOL NEAR ImportFile( HWND );
  75. BOOL NEAR GetExtFilter( void );
  76. HDC NEAR GetPrinterIC( void );
  77.  
  78.  
  79.  
  80. [LISTING TWO]
  81.  
  82. /****************************************************************************
  83.  
  84.     FILE   : Viewer.c
  85.  
  86.     PURPOSE: Graphics file viewer
  87.  
  88.     FUNCTIONS:
  89.  
  90.     WinMain() - calls initialization function, processes message loop
  91.     MainWndProc() - processes messages
  92.     ImportFile() - Converts graphics file to Windows Metafile
  93.     GetExtFilter() - Determines correct filter for chosen file
  94.     GetPrinterIC() - Determines current printer
  95.     AboutDlgProc() - processes messages for "About" dialog box
  96.  
  97.     COMMENTS:
  98.  
  99. ) 1992, Evangelo Prodromou.  All rights reserved.
  100. ****************************************************************************/
  101.  
  102. /* include the general Windows header and the header for this application. */
  103.  
  104. #include "windows.h"                
  105. #include "viewer.h"
  106.  
  107. /* These strings are used repeatedly. */
  108.  
  109. char    szAppName[ ]            = "GraphicViewer";        
  110. char    szClassName[ ]          = "ViewerWClass";
  111. char    szMenuName[ ]           = "ViewerMenu";
  112.  
  113. char    szString[ STRINGSIZE ];          /* General use string. */
  114. char    szFilter[ IBMFNSIZE ];  /* full path name of import filter. */
  115.  
  116. /* Info struct of the imported metafile. */
  117.  
  118. PICTINFO PictInfo = { NULL,0,0,0,0,0 };
  119.  
  120. /* Spec struct for file to import. */
  121.  
  122. FILESPEC FileSpec = { 0,0,0,0,0,0L,NULL };
  123.  
  124. HANDLE  hInst;                    /* Handle for this instance. */
  125.  
  126. /***************************************************************************
  127.  
  128. FUNCTION: WinMain
  129. PURPOSE:  Entrance point of application
  130.  
  131. ARGS:     hInstance     : handle to this instance.
  132.       hPrevInstance : handle to previous instance of the application.
  133.       lpCmdLine     : command line string
  134.       nCmdShow      : show full or iconic? Passed to ShowWindow()
  135.    
  136. COMMENTS: If no previous instance, registers the window class.
  137.       Saves this instance handle as a global variable.  
  138.       Parses command line for a file name to view.  
  139.       Creates window for this instance. 
  140.       Shows the window.
  141.       Takes and translates messages from the message loop and passes
  142.          them on to MainWndProc().
  143.  
  144. ***************************************************************************/
  145. int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
  146.             LPSTR lpCmdLine, int nCmdShow)
  147. {
  148.     MSG             msg;    /* Windows message structure */                                 
  149.     WNDCLASS        wc;     /* Window class structure. */
  150.     HWND            hMain;  /* handle to main window.  */
  151.  
  152. /* If there is no previous instance of the application, fill in the 
  153. ** window class structure and register the class. */
  154.  
  155.     if (!hPrevInstance)
  156.     {       
  157.         wc.style =              NULL;                    
  158.         wc.lpfnWndProc =        MainWndProc;       
  159.         wc.cbClsExtra =         0;                  
  160.         wc.cbWndExtra =         0;                  
  161.         wc.hInstance =          hInstance;           
  162.         wc.hIcon =              LoadIcon(NULL, IDI_APPLICATION);
  163.         wc.hCursor =            LoadCursor(NULL, IDC_ARROW);
  164.         wc.hbrBackground =      GetStockObject(WHITE_BRUSH); 
  165.         wc.lpszMenuName =       (LPSTR) szMenuName;   
  166.         wc.lpszClassName =      (LPSTR) szClassName; 
  167.  
  168.         if (!RegisterClass(&wc))
  169.             return FALSE;
  170.     }       
  171.  
  172. /* Save the instance handle as a global variable. */
  173.  
  174.     hInst = hInstance;
  175.          
  176. /* Copy the command line argument to the filename field of FileSpec. */
  177.  
  178.     lstrcpy( FileSpec.fullName,  lpCmdLine );
  179.     
  180. /* Create the main window (will send WM_CREATE to the MainWndProc). */
  181.  
  182.     hMain = CreateWindow( szClassName, szAppName,         
  183.             WS_OVERLAPPEDWINDOW,            
  184.             CW_USEDEFAULT, CW_USEDEFAULT,                  
  185.             CW_USEDEFAULT, CW_USEDEFAULT,                  
  186.             NULL, NULL, hInstance, NULL );
  187.  
  188.     if (!hMain)
  189.         return (FALSE);
  190.  
  191. /* Show the window and update it ( sends WM_PAINT to MainWndProc ). */
  192.  
  193.     ShowWindow(hMain, nCmdShow);  
  194.     UpdateWindow(hMain);
  195.  
  196. /* Get window messages for this instance and send them to the MainWndProc. 
  197. ** Loops until WM_QUIT message is received. */
  198.  
  199.     while ( GetMessage( &msg,NULL,NULL,NULL )  )            
  200.     {
  201.         TranslateMessage( &msg );    
  202.         DispatchMessage( &msg );     
  203.     }
  204.     return ( msg.wParam );       
  205. }
  206.  
  207. /***************************************************************************
  208.  
  209. FUNCTION: MainWndProc
  210. PURPOSE:  Processes messages for main window
  211.  
  212. ARGS:     hWnd          : handle to main window
  213.       message       : windows message
  214.       wParam        : extra message info
  215.       lParam        : extra message info
  216.    
  217. MESSAGES: WM_CREATE     : If a file was specified on the command line, gets
  218.               the correct filter by extension, and tries to
  219.               import it.  If no file specified, or if no matching
  220.               filter is found, asks for a new file.
  221.  
  222.       WM_PAINT      : If a file has been imported, displays the 
  223.               resulting metafile.  Otherwise, passes the message
  224.               to default.
  225.  
  226.       WM_SIZE       : Invalidate whole client area, and repaint.
  227.  
  228.       WM_DESTROY    : Terminates program.
  229.  
  230.       WM_COMMAND    : IDM_ABOUT     : Displays About dialog box.
  231.  
  232. ***************************************************************************/
  233.  
  234. long FAR PASCAL MainWndProc(HWND hWnd, unsigned message, 
  235.                 WORD wParam, LONG lParam)
  236. {
  237.     FARPROC lpProc;               
  238.     BOOL    bError;
  239.     RECT        rc;
  240.  
  241.     switch (message) 
  242.     {
  243.     case WM_CREATE:
  244.  
  245.         /* Assume an error to begin with. */
  246.  
  247.         bError = TRUE;
  248.  
  249.         if ( FileSpec.fullName[0] == '\0' ) /* No file name on command line */
  250.         {
  251.         lstrcpy( (LPSTR) szString, "No file name specified." );
  252.         }
  253.         else if ( !GetExtFilter( ) ) /* Unable to find filter */
  254.         {
  255.         lstrcpy( (LPSTR) szString, 
  256.             "No filter specified in WIN.INI for file extension." );
  257.         }
  258.         else if ( !ImportFile( hWnd ) ) /* Unable to import */
  259.         {
  260.         lstrcpy( (LPSTR) szString, "Unable to import file." );
  261.         }   
  262.         else bError = FALSE;  /* Import was a success */
  263.  
  264.         if (bError) 
  265.         {
  266.         MessageBox( hWnd, (LPSTR) szString, 
  267.                       (LPSTR) szAppName,
  268.                       MB_OK | MB_ICONHAND );
  269.         DestroyWindow( hWnd );
  270.         }
  271.         break;
  272.     
  273.  
  274.     case WM_PAINT:     /* Paint window by playing metafile. */
  275.  
  276.         if ( PictInfo.hmf ) /* A file has been imported. */
  277.         {
  278.             PAINTSTRUCT     ps;
  279.             HDC             hDC = BeginPaint( hWnd, &ps );
  280.  
  281.             SetMapMode( hDC, MM_ANISOTROPIC );
  282.             SetWindowExt( hDC, PictInfo.bbox.right - PictInfo.bbox.left,
  283.                        PictInfo.bbox.bottom - PictInfo.bbox.top );
  284.             GetClientRect( hWnd, &rc );
  285.             SetViewportExt( hDC, rc.right - rc.left, rc.bottom - rc.top );
  286.  
  287.             SetWindowOrg( hDC, PictInfo.bbox.left, PictInfo.bbox.top );
  288.             PlayMetaFile( hDC, PictInfo.hmf );
  289.  
  290.             EndPaint( hWnd, &ps );
  291.         }
  292.         break;
  293.  
  294.     case WM_SIZE:  /* Invalidate, and paint full window. */
  295.  
  296.         GetClientRect( hWnd, &rc );
  297.         InvalidateRect( hWnd, &rc, TRUE);
  298.         UpdateWindow( hWnd );
  299.         break;
  300.  
  301.     case WM_DESTROY:  /* Send WM_QUIT message to message loop to end. */
  302.  
  303.         PostQuitMessage( hWnd );
  304.         break;
  305.  
  306.     case WM_COMMAND:  /* Creates About dialog box. */
  307.        
  308.         if ( wParam == IDM_ABOUT )
  309.         {
  310.             lpProc = MakeProcInstance( AboutDlgProc, hInst );
  311.  
  312.             DialogBox( hInst, "AboutBox", hWnd, lpProc );
  313.         
  314.             FreeProcInstance( lpProc );
  315.             
  316.             break;
  317.         }  /* Otherwise, fall through to default. */
  318.  
  319.     default:
  320.               
  321.         return ( DefWindowProc( hWnd, message, wParam, lParam ) );
  322.     }
  323.     return (NULL);
  324. }
  325.  
  326. /***************************************************************************
  327. *                                                                          *
  328. *       FUNCTION: ImportFile                                               *
  329. *       PURPOSE : Translate a graphic file to a metafile using a filter    *
  330. *                                                                          *
  331. *       ARGS    : HWND hWnd - handle to main window.                       *
  332. *       RETURN  : TRUE if file import is successful, otherwise FALSE.      *
  333. *                                                                          *
  334. *       COMMENTS: Loads a filter DLL into memory, and uses it's import     *
  335. *                 functionality to translate a graphic file to a metafile. *
  336. *                 Uses Aldus-standard interface functions, version 1 or 2. *
  337. *                                                                          *
  338. ***************************************************************************/
  339.  
  340. BOOL NEAR ImportFile(HWND hWnd)
  341. {
  342.     HANDLE          hFilter = NULL, hPrefMem = NULL;
  343.     WORD            wFilterResult = -1;
  344.     HDC             hPrintIC = NULL;
  345.  
  346. /* Version 1.0 Filter functions */
  347.  
  348.     PFN_INFO        lpfnGetFilterInfo = NULL;
  349.     PFN_IMPORT      lpfnImportGR = NULL;
  350.     PFN_PREF        lpfnGetFilterPref = NULL;
  351.  
  352. /* Version 2.0 Filter functions */
  353.  
  354.     PFN_VER         lpfnGetFilterVersion = NULL;
  355.     PFN_ISMY        lpfnIsThisMyFile = NULL;
  356.     PFN_PREF2       lpfnGetFilterPref2 = NULL;
  357.     PFN_OUTPUT      lpfnOutputGR = NULL;
  358.  
  359. /* Load appropriate filter. */
  360.  
  361.     hFilter = LoadLibrary( (LPSTR) szFilter );
  362.  
  363. /* Try to find "GetFilterVersion." */
  364.  
  365.     lpfnGetFilterVersion = GetProcAddress( hFilter, 
  366.                      "GetFilterVersion" );
  367.  
  368.     if ( !lpfnGetFilterVersion ) /* This is a v 1.0 filter. */
  369.     {
  370.  
  371.         lpfnGetFilterInfo = GetProcAddress( hFilter, 
  372.                         "GetFilterInfo" );
  373.  
  374.         if ( lpfnGetFilterInfo )
  375.         {
  376.             wFilterResult = (*lpfnGetFilterInfo)( 2, 
  377.                         NULL, 
  378.                         &hPrefMem, 
  379.                         NULL );
  380.         } 
  381.  
  382. /* Call filter's GetFilterPref function, which creates a "filter preference"
  383. ** dialog box to set import options. */
  384.  
  385.         lpfnGetFilterPref = GetProcAddress( hFilter, 
  386.                         "GetFilterPref" );
  387.  
  388.         if ( lpfnGetFilterPref )
  389.         {   
  390.             (*lpfnGetFilterPref)( hInst, hWnd, hPrefMem, 1 );
  391.         }
  392.  
  393. /* Call filter's ImportGR function to convert the file to a Windows
  394. ** metafile (information is stored in FileSpec). */
  395.  
  396.  
  397.         lpfnImportGR = GetProcAddress( hFilter, "ImportGR" );
  398.         if ( lpfnImportGR )
  399.         {
  400.             hPrintIC = GetPrinterIC();
  401.  
  402.             wFilterResult = (*lpfnImportGR)( hPrintIC, 
  403.                              &FileSpec, 
  404.                              &PictInfo, 
  405.                              hPrefMem );
  406.         }
  407.     }
  408.     
  409.     else /* This is a v. 2.0 or higher filter. */
  410.     {
  411.  
  412. /* Ensure that current file is compatible with current filter. */
  413.  
  414.         lpfnIsThisMyFile = GetProcAddress( hFilter, 
  415.                         "IsThisMyFile" );
  416.         
  417.         if ( lpfnIsThisMyFile )
  418.         {
  419.  
  420.             (*lpfnIsThisMyFile) ( &FileSpec );
  421.  
  422.         }
  423.  
  424. /* Get user's import preferences. */
  425.  
  426.         lpfnGetFilterPref2 = GetProcAddress( hFilter, "GetFilterPref" );
  427.         if (lpfnGetFilterPref2)
  428.         {
  429.             wFilterResult = (*lpfnGetFilterPref2) ( hInst,
  430.                                hWnd,
  431.                                &hPrefMem,
  432.                                FileSpec.fType,
  433.                                NULL,
  434.                                &FileSpec);
  435.         }
  436. /* Convert chosen file to a metafile. */
  437.  
  438.         lpfnOutputGR = GetProcAddress( hFilter, "OutputGR" );
  439.         if (lpfnOutputGR)
  440.         {
  441.             hPrintIC = GetPrinterIC();
  442.  
  443.             wFilterResult = (*lpfnOutputGR) ( NULL,
  444.                             hPrintIC,
  445.                             &FileSpec,
  446.                             NULL,
  447.                             &PictInfo,
  448.                             hPrefMem,
  449.                             NULL,
  450.                             FALSE);
  451.         }
  452.     }
  453.  
  454. /* Free the memory allocated to the filter DLL and the preference memory.*/
  455.  
  456.     FreeLibrary( hFilter );
  457.     GlobalFree( hPrefMem );
  458.  
  459. /* Set the window title to the file name, or return false. */
  460.  
  461.     if ( wFilterResult == 0 ) 
  462.     {
  463.         SetWindowText( hWnd, FileSpec.fullName );
  464.         return TRUE;
  465.     }
  466.     else
  467.     {
  468.         return FALSE;
  469.     }
  470. }
  471.  
  472. /***************************************************************************
  473. *                                                                          *
  474. *       FUNCTION: GetExtFilter                                             *
  475. *       PURPOSE : Get filename of filter appropriate for current file.     *
  476. *                                                                          *
  477. *       ARGS    : none                                                     *
  478. *       RETURN  : TRUE if able to find filter, otherwise FALSE.            *
  479. *                                                                          *
  480. *       COMMENTS: Gets all filter names listed under [GraphicViewer]       *
  481. *                 heading in WIN.INI.  Checks which one entry supports     *
  482. *                 files with the same extension as FileSpec.fullName.      *
  483. *                                                                          *
  484. ***************************************************************************/
  485.  
  486. BOOL NEAR GetExtFilter( void )
  487. {
  488.     PSTR pDesc, pExt, pSupExt;
  489.     int  nLen = lstrlen( FileSpec.fullName );
  490.     char szItem[ IBMFNSIZE + 4 ];
  491.  
  492.     /* Set pExt to last char in FileSpec.fullName. */
  493.  
  494.     if (!nLen) return FALSE;
  495.  
  496.     pExt = FileSpec.fullName + nLen - 1; 
  497.     
  498.     while ( *(pExt - 1) != '.' )
  499.     {
  500.         pExt--;
  501.         if (pExt == FileSpec.fullName) return FALSE;
  502.     }
  503.  
  504.     /* get all profile string entries (description of filter). */
  505.  
  506.     nLen = GetProfileString( szAppName, NULL, NULL, szString, STRINGSIZE );
  507.  
  508.     /* start with the first description. */
  509.     
  510.     pDesc = szString;
  511.  
  512.     /* while we still have a string to check... */
  513.  
  514.     while ( pDesc < szString + nLen )
  515.     {
  516.         /* get the entry for this filter
  517.         ("[filter file name],[ext]") */
  518.  
  519.         GetProfileString( (LPSTR) szAppName, (LPSTR) pDesc, 
  520.                   NULL, (LPSTR) szItem, IBMFNSIZE + 4 );
  521.         
  522.         /* if one exists, and its extension matches the file
  523.         ** extension... */
  524.  
  525.         strcpy( szFilter, strtok( szItem, "," ) );
  526.         pSupExt = strtok( NULL, ", " );
  527.  
  528.         if( lstrcmpi( (LPSTR) pExt, (LPSTR) pSupExt ) == 0 )
  529.         {
  530.             *(pSupExt-1) = '\0'; 
  531.             return TRUE;
  532.         }
  533.         else
  534.         {
  535.                /* move on to next filter. */
  536.                pDesc += lstrlen( (LPSTR) pDesc ) + 1;
  537.         }
  538.     }
  539.  
  540.     /* if we get here, we couldn't find one. Make sure szFilter is blank.*/
  541.     
  542.     szFilter[0] = '\0';
  543.  
  544.     /* Report failure. */
  545.  
  546.     return FALSE;
  547. }
  548.  
  549. /***************************************************************************
  550. *                                                                          *
  551. *       FUNCTION: GetPrinterIC                                             *
  552. *       PURPOSE : Get information context for active print device.         *
  553. *                                                                          *
  554. *       ARGS    : none                                                     *
  555. *       RETURN  : handle to printer's information context or NULL if fail. *
  556. *                                                                          *
  557. *       COMMENTS: Gets device description from [windows] heading in        *
  558. *                 WIN.INI.  Breaks down the description into device name,  *
  559. *                 driver name, and output port.  Uses CreateIC() to get    *
  560. *                 an information context.                                  *
  561. *                                                                          *
  562. ***************************************************************************/
  563.  
  564. HDC GetPrinterIC( void )
  565. {
  566.     PSTR pDevice, pDriver, pOutput;
  567.     HDC  hReturn = NULL;
  568.     
  569. /* Get the information on the current printer, listed under "windows" in
  570. ** WIN.INI as "device=[device name],[driver],[output port]". */
  571.  
  572.     GetProfileString("windows", "device", NULL,
  573.                     (LPSTR) szString, STRINGSIZE);
  574.  
  575.     if ( ( pDevice = strtok( szString, "," ) ) &&
  576.          ( pDriver = strtok( NULL,     ", " ) ) &&
  577.          ( pOutput = strtok( NULL,     ", " ) ) )
  578.     {
  579.         hReturn = CreateIC( (LPSTR) pDriver, (LPSTR) pDevice,
  580.                     (LPSTR) pOutput, NULL );
  581.     }
  582.  
  583.     return ( hReturn ); 
  584. }
  585.  
  586. /***************************************************************************
  587. *                                                                          *
  588. *       FUNCTION: AboutDlgProc                                             *
  589. *       PURPOSE : Handles messages for AboutBox dialog box.                *
  590. *                                                                          *
  591. *       ARGS    : Standard callback arguments.                             *
  592. *       RETURN  : N/A.                                                     *
  593. *                                                                          *
  594. *       COMMENTS: Closes AboutBox when OK button, Enter or ESC are pressed.*
  595. *                                                                          *
  596. ***************************************************************************/
  597.  
  598.  
  599. BOOL FAR PASCAL AboutDlgProc(HWND hDlg, unsigned message, 
  600.                 WORD wParam, LONG lParam)
  601. {
  602.     switch (message) 
  603.     {
  604.     case WM_INITDIALOG:  /* Beginning. No functionality. */              
  605.         
  606.         return (TRUE);
  607.  
  608.     case WM_COMMAND:
  609.               
  610.         switch (wParam)
  611.         {
  612.             case IDOK:  /* OK or Enter were pressed. */              
  613.             case IDCANCEL: /* Esc was pressed. */
  614.         
  615.                 EndDialog(hDlg, TRUE);        
  616.                 return (TRUE);
  617.         }
  618.         break;
  619.     }
  620.     return (FALSE);                           
  621. }
  622.  
  623.  
  624.  
  625.  
  626.  
  627.